﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.Xml.Serialization;
using System.ComponentModel;

namespace ViewMaker.Core.Controls
{
    /// <summary>
    /// パネルViewコントロール
    /// </summary>
    public abstract class PanelViewControl : ViewControl, IHeaderPropProvider
    {
        /// <summary>
        /// プロパティ定数
        /// </summary>
        public new class Properties : ViewControl.Properties
        {
            public const string HeaderPosition = "HeaderPosition";
            public const string HeaderWidth = "HeaderWidth";
            public const string HeaderHeight = "HeaderHeight";
            public const string HeaderHorizontalContentAlignment = "HeaderHorizontalContentAlignment";
            public const string HeaderFontSize = "HeaderFontSize";
            public const string HeaderForeground = "HeaderForeground";
            public const string HeaderBackground = "HeaderBackground";

            public const string HasHeader = "HasHeader";            
            public const string ItemWidth = "ItemWidth";
            public const string ItemHeight = "ItemHeight";
            public const string ItemMargin = "ItemMargin";
            public const string Margin = "Margin";

            public const string LoadCommand = "LoadCommand";
            public const string UnloadCommand = "UnloadCommand";
        }

        /// <summary>
        /// パネルに配置されたコントロールの既定のヘッダー位置
        /// </summary>
        [Display(Name = "Header Position", GroupName = LayoutGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "HeaderPositionList")]
        public LayoutHeaderPosition HeaderPosition { get; set; }

        /// <summary>
        /// パネルに配置されたコントロールの既定のヘッダー幅
        /// </summary>
        [Display(Name = "Header Width", GroupName = LayoutGroup)]
        public int? HeaderWidth { get; set; }

        /// <summary>
        /// パネルに配置されたコントロールの既定のヘッダー高さ
        /// </summary>
        [Display(Name = "Header Height", GroupName = LayoutGroup)]
        public int? HeaderHeight { get; set; }

        /// <summary>
        /// パネルに配置されたコントロールの既定のヘッダーコンテンツの水平配置位置
        /// </summary>
        [Display(Name = "Header HAlign", Description = "Header Horizontal Alignment", GroupName = LayoutGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "HorizontalAlignmentList")]
        public LayoutHorizontalAlignment? HeaderHorizontalContentAlignment { get; set; }

        /// <summary>
        /// パネルに配置されたコントロールの既定のヘッダーフォントサイズ
        /// </summary>
        [Display(Name = "Header FontSize", GroupName = StyleGroup)]
        public double? HeaderFontSize { get; set; }

        /// <summary>
        /// パネルに配置されたコントロールの既定のヘッダー前景色
        /// </summary>
        [Display(Name = "Header Foreground", GroupName = StyleGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "ColorList")]
        [ViewProperty(ComboBoxViewControl.Properties.IsEditable, true)]
        public string HeaderForeground { get; set; }

        /// <summary>
        /// パネルに配置されたコントロールの既定のヘッダー背景色
        /// </summary>
        [Display(Name = "Header Background", GroupName = StyleGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "ColorList")]
        [ViewProperty(ComboBoxViewControl.Properties.IsEditable, true)]
        public string HeaderBackground { get; set; }

        /// <summary>
        /// パネルのヘッダーを表示するか
        /// </summary>
        [Display(Description = "Header Visibility", GroupName = StyleGroup)]
        public bool HasHeader { get; set; }

        /// <summary>
        /// パネルに配置されたコントロールの既定の幅
        /// </summary>
        [Display(Name = "Item Width", GroupName = LayoutGroup)]
        public int? ItemWidth { get; set; }

        /// <summary>
        /// パネルに配置されたコントロールの既定の高さ
        /// </summary>
        [Display(Name = "Item Height", GroupName = LayoutGroup)]
        public int? ItemHeight { get; set; }

        /// <summary>
        /// パネルに配置されたコントロールの既定のマージン
        /// </summary>
        [Display(Name = "Item Margin", GroupName = LayoutGroup)]
        public string ItemMargin { get; set; }

        /// <summary>
        /// パネル自身のマージン
        /// </summary>
        [Display(GroupName = LayoutGroup)]
        public string Margin { get; set; }

        /// <summary>
        /// ロード時に実行するコマンド
        /// </summary>
        [Display(GroupName = CommandGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "Item.CommandList")]
        [ViewProperty(ComboBoxViewControl.Properties.IsEditable, true)]
        public string LoadCommand { get; set; }

        /// <summary>
        /// アンロード時に実行するコマンド
        /// </summary>
        [Display(GroupName = CommandGroup)]
        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "Item.CommandList")]
        [ViewProperty(ComboBoxViewControl.Properties.IsEditable, true)]
        public string UnloadCommand { get; set; }

        [XmlIgnore]
        [Browsable(false)]
        public override bool CanAddChild { get { return true; } }

        [XmlIgnore]
        [Browsable(false)]
        public override bool CanOverrideWidth { get { return false; } }

        [XmlIgnore]
        [Browsable(false)]
        public override bool CanOverrideHeight { get { return false; } }

        #region ShouldSerialize

        public virtual bool ShouldSerializeHeaderWidth() { return HeaderWidth.HasValue; }
        public virtual bool ShouldSerializeItemWidth() { return true; }
        public virtual bool ShouldSerializeHeaderHorizontalContentAlignment() { return HeaderHorizontalContentAlignment.HasValue; }
        public override bool ShouldSerializeVerticalAlignment() { return true; }
        public override bool ShouldSerializeHorizontalAlignment() { return true; }
        public virtual bool ShouldSerializeHeaderFontSize() { return HeaderFontSize.HasValue; }

        #endregion


        public PanelViewControl()
        {
            Margin = ViewMakerSettings.Instance.DefaultPanelMargin ?? "";
            HeaderPosition = ViewMakerSettings.Instance.DefaultPanelHeaderPosition;
            VerticalAlignment = LayoutVerticalAlignment.Stretch;
            HorizontalAlignment = LayoutHorizontalAlignment.Stretch;
            Height = null;
        }

        protected List<XamlNode> CreateHeaderControl(ViewLayoutItem headerItem, XamlNode parent)
        {
            var headerControl = headerItem.Element as HeaderViewControl;
            if (headerControl == null) return null;

            if (headerControl.IsComposite)
            {
                return new List<XamlNode> { CreateCompositeHeaderControl(headerItem, parent) };
            }
            else
            {
                int idx=0;
                var nodes = headerItem.CreateXaml(parent);
                foreach (var node in nodes)
                {
                    if (idx == 0 && headerControl.ActualHeaderPosition == LayoutHeaderPosition.Flat)
                    {
                        SetHeaderAttribute(headerControl, node);
                        if (!node.HasAttribute("Margin") && !string.IsNullOrEmpty(ItemMargin)) node.SetAttribute("Margin", ItemMargin);
                    }else{
                        SetItemAttribute(headerItem, node);
                    }
                    idx++;
                }
                return nodes;
            }
        }

        private XamlNode CreateCompositeHeaderControl(ViewLayoutItem headerItem, XamlNode parent)
        {
            var headerControl = headerItem.Element as HeaderViewControl;
            var panel = parent.CreateElement("Grid");
            if (headerControl.ActualHeaderPosition == LayoutHeaderPosition.Left)
            {
                var columns = panel.AddElement("Grid.ColumnDefinitions");
                var col1 = columns.AddElement("ColumnDefinition");
                var col2 = columns.AddElement("ColumnDefinition");
                col1.SetAttribute("Width", "auto");
                col2.SetAttribute("Width", "*");
            }
            else
            {
                var rows = panel.AddElement("Grid.RowDefinitions");
                var row1 = rows.AddElement("RowDefinition");
                var row2 = rows.AddElement("RowDefinition");
                row1.SetAttribute("Height", "auto");
                row2.SetAttribute("Height", "*");
            }
            SetCompositePanelAttribute(headerItem, panel);

            int itemIdx = 0;
            foreach (var item in headerItem.CreateXaml(panel))
            {
                if (itemIdx == 0)
                {
                    SetHeaderAttribute(headerControl, item);
                }
                else
                {
                    SetCompositeItemAttribute(headerItem, item);
                    if (headerControl.ActualHeaderPosition == LayoutHeaderPosition.Left)
                    {
                        item.SetAttribute("Grid.Column", "1");
                    }
                    else
                    {
                        item.SetAttribute("Grid.Row", "1");
                    }
                }
                panel.AppendChild(item);
                itemIdx++;
            }
            return panel;
        }

        protected void SetHeaderAttribute(HeaderViewControl headerControl, XamlNode item)
        {
            if (headerControl.HeaderVerticalAlignment.HasValue) item.SetAttribute("VerticalAlignment", headerControl.HeaderVerticalAlignment.ToString());
 
            //silverlightのLabelにHorizontalAlignmentを指定するとHorizontalContentAlignmentを上書きする問題があるためTopのときのみ設定するようにしている
            if (headerControl.ActualHeaderPosition == LayoutHeaderPosition.Top) item.SetAttribute("HorizontalAlignment", LayoutHorizontalAlignment.Left.ToString());
        }

        private void SetCompositeItemAttribute(ViewLayoutItem targetItem, XamlNode targetXaml)
        {
            if (!targetItem.Control.Width.HasValue && targetItem.Element.CanOverrideWidth && ItemWidth.HasValue) targetXaml.SetAttribute("Width", ItemWidth.ToString());
            targetXaml.SetAttribute("VerticalAlignment", LayoutVerticalAlignment.Center.ToString());
        }

        private void SetCompositePanelAttribute(ViewLayoutItem targetItem, XamlNode targetXaml)
        {
            if (targetItem.Control.VerticalAlignment.HasValue) targetXaml.SetAttribute("VerticalAlignment", targetItem.Control.VerticalAlignment.ToString());
            if (targetItem.Control.HorizontalAlignment.HasValue)
            {
                targetXaml.SetAttribute("HorizontalAlignment", targetItem.Control.HorizontalAlignment.ToString());
            }
            else if (targetItem.Control.Width.HasValue)
            {
                targetXaml.SetAttribute("HorizontalAlignment", LayoutHorizontalAlignment.Left.ToString());
            }
            if (!targetXaml.HasAttribute("Margin") && !string.IsNullOrEmpty(ItemMargin)) targetXaml.SetAttribute("Margin", ItemMargin);
        }

        protected virtual void SetItemAttribute(ViewLayoutItem targetItem, XamlNode targetXaml)
        {
            if (targetItem.Control.VerticalAlignment.HasValue) targetXaml.SetAttribute("VerticalAlignment", targetItem.Control.VerticalAlignment.ToString());
            if (targetItem.Control.HorizontalAlignment.HasValue)
            {
                targetXaml.SetAttribute("HorizontalAlignment", targetItem.Control.HorizontalAlignment.ToString());
            }
            else if (targetItem.Control.Width.HasValue)
            {
                targetXaml.SetAttribute("HorizontalAlignment", LayoutHorizontalAlignment.Left.ToString());
            }
            if (!targetXaml.HasAttribute("Margin") && !string.IsNullOrEmpty(ItemMargin)) targetXaml.SetAttribute("Margin", ItemMargin);
        }


        protected override void ApplyBaseProperty(XamlNode node)
        {
            base.ApplyBaseProperty(node);
            if (!string.IsNullOrEmpty(Margin)) node.SetAttribute("Margin", Margin);
            var back = GetBackground();
            if (!string.IsNullOrEmpty(back)) node.SetAttribute("Foreground", null);
            if (!string.IsNullOrEmpty(LoadCommand)) AddBehavior(node, "LoadBehavior", LoadCommand);
            if (!string.IsNullOrEmpty(UnloadCommand)) AddBehavior(node, "UnloadBehavior", UnloadCommand);
#if SILVERLIGHT
            node.SetAttribute("IsEnabled", null);            
#endif
        }
        public XamlNode Decoration
        {
            get { return _decoration; }
        }
        private XamlNode _decoration;

        protected XamlNode CreatePanel(XamlNode parent, string element)
        {
            _decoration = null;
            XamlNode panel;
            if (HasHeader) _decoration = CreateHeaderedContentControl(parent);
#if SILVERLIGHT
            if (!string.IsNullOrEmpty(IsEnabled))
            {
                if (_decoration == null) _decoration = parent.CreateElement("ContentControl");
                SetBindingAttribute(_decoration, "IsEnabled", IsEnabled, true);
                _decoration.SetAttribute("HorizontalContentAlignment", LayoutHorizontalAlignment.Stretch.ToString());
            }
#endif
            if (_decoration != null)
            {
                panel = _decoration.AddElement(element);
            }
            else
            {
                panel = parent.CreateElement(element);
            }
            return panel;
        }


        protected XamlNode CreateHeaderedContentControl(XamlNode parent)
        {
            XamlNode header;
#if !SILVERLIGHT
            header = parent.CreateElement("HeaderedContentControl");


#else
                header = parent.CreateElement("toolkit", "clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit", "HeaderedContentControl");
                header.SetAttribute("HorizontalContentAlignment", LayoutHorizontalAlignment.Stretch.ToString());                
#endif
            header.SetAttribute("Header", Item.Caption ?? "");
            var fontSize = GetFontSize();
            if (fontSize.HasValue) header.SetAttribute("FontSize", fontSize.ToString());
            var fore = GetForeground();
            if (!string.IsNullOrEmpty(fore)) header.SetAttribute("Foreground", fore);
            var back = GetBackground();
            if (!string.IsNullOrEmpty(back)) header.SetAttribute("Background", back);
            return header;
        }

        internal override void CopyFrom(ViewElement source)
        {
            base.CopyFrom(source);
            var panel = source as PanelViewControl;
            if (panel == null) return;
            this.HeaderPosition = panel.HeaderPosition;
            if (panel.HeaderWidth.HasValue) this.HeaderWidth = panel.HeaderWidth;
            if (panel.HeaderHorizontalContentAlignment.HasValue) this.HeaderHorizontalContentAlignment = panel.HeaderHorizontalContentAlignment;
            if (panel.ItemWidth.HasValue) this.ItemWidth = panel.ItemWidth;
            if (!string.IsNullOrEmpty(panel.Margin)) this.Margin = panel.Margin;
            if (!string.IsNullOrEmpty(panel.ItemMargin)) this.ItemMargin = panel.ItemMargin;
            this.HeaderFontSize = panel.HeaderFontSize;
            this.HeaderForeground = panel.HeaderForeground;
            this.HeaderBackground = panel.HeaderBackground;
            this.LoadCommand = panel.LoadCommand;
            this.UnloadCommand = panel.UnloadCommand;
        }

        #region IHeaderPropProvider メンバー

        public virtual LayoutHorizontalAlignment? GetHeaderHorizontalContentAlignment(ViewControl ctrl)
        {
            if (HeaderHorizontalContentAlignment.HasValue) return HeaderHorizontalContentAlignment;
            if (this.Item.Parent != null)
            {
                var header = this.Item.Parent.Element as IHeaderPropProvider;
                if (header != null) return header.GetHeaderHorizontalContentAlignment(ctrl);
            }
            return null;
        }

        public virtual LayoutVerticalAlignment? GetHeaderVerticalAlignment(ViewControl ctrl)
        {
            if (VerticalAlignment.HasValue) return VerticalAlignment;
            if (this.Item.Parent != null)
            {
                var header = this.Item.Parent.Element as IHeaderPropProvider;
                if (header != null) return header.GetHeaderVerticalAlignment(ctrl);
            }
            return null;
        }

        public virtual int? GetHeaderWidth(ViewControl ctrl)
        {
            if (HeaderWidth.HasValue) return HeaderWidth;
            if (this.Item.Parent != null)
            {
                var header = this.Item.Parent.Element as IHeaderPropProvider;
                if (header != null) return header.GetHeaderWidth(ctrl);
            }
            return null;
        }

        public virtual int? GetHeaderHeight(ViewControl ctrl)
        {
            if (HeaderHeight.HasValue) return HeaderHeight;
            if (this.Item.Parent != null)
            {
                var header = this.Item.Parent.Element as IHeaderPropProvider;
                if (header != null) return header.GetHeaderHeight(ctrl);
            }
            return null;
        }

        public virtual double? GetHeaderFontSize(ViewControl ctrl)
        {
            if (HeaderFontSize.HasValue) return HeaderFontSize;
            if (this.Item.Parent != null)
            {
                var header = this.Item.Parent.Element as IHeaderPropProvider;
                if (header != null) return header.GetHeaderFontSize(ctrl);
            }
            return null;
        }

        public virtual string GetHeaderForeground(ViewControl ctrl)
        {
            if (!string.IsNullOrEmpty(HeaderForeground)) return HeaderForeground;
            if (this.Item.Parent != null)
            {
                var header = this.Item.Parent.Element as IHeaderPropProvider;
                if (header != null) return header.GetHeaderForeground(ctrl);
            }
            return null;
        }

        public virtual string GetHeaderBackground(ViewControl ctrl)
        {
            if (!string.IsNullOrEmpty(HeaderBackground)) return HeaderBackground;
            if (this.Item.Parent != null)
            {
                var header = this.Item.Parent.Element as IHeaderPropProvider;
                if (header != null) return header.GetHeaderBackground(ctrl);
            }
            return null;
        }

        #endregion

        #region IItemPropProvider Members

        public override int? GetItemWidth(ViewControl ctrl)
        {
            if (ctrl == this) return ctrl.Width;
            if (this.ItemWidth.HasValue) return this.ItemWidth;
            if (this.Item.Parent != null)
            {
                var provider = this.Item.Parent.Element as IItemPropProvider;
                if (provider != null) return provider.GetItemWidth(ctrl);

            }
            return null;
        }

        public override int? GetItemHeight(ViewControl ctrl)
        {
            if (ctrl == this) return ctrl.Height;
            if (this.ItemHeight.HasValue) return this.ItemWidth;
            if (this.Item.Parent != null)
            {
                var provider = this.Item.Parent.Element as IItemPropProvider;
                if (provider != null) return provider.GetItemHeight(ctrl);

            }
            return null;
        }

    //    public override string GetItemMargin(ViewControl ctrl)
    //    {
    //        if (!string.IsNullOrEmpty(ItemMargin)) return ItemMargin;
    //        if (this.Item.Parent != null)
    //        {
    //            var provider = this.Item.Parent.Control as IItemPropProvider;
    //            if (provider != null) return provider.GetItemMargin(ctrl);
    //        }
    //        return null;
    //    }

    //    public override LayoutHorizontalAlignment? GetHorizontalAlignment(ViewControl ctrl)
    //    {
    //        var align = base.GetHorizontalAlignment(ctrl);
    //        if (align.HasValue) return align;
    //        if (ctrl.Width.HasValue) return LayoutHorizontalAlignment.Left;
    //        return null;
        //    }
        #endregion
    }

}
